<!DOCTYPE html>
<html>

<head>
    <title>传统法计算二次贝塞尔曲线和直线的交点</title>
    <!-- <script src="Point.js"></script> -->
</head>

<body>
    <!-- <canvas width="800" height="800" id="canvas"></canvas> -->
    <a href="https://blog.csdn.net/iloveas2014/article/details/83119492">连接</a>
    <canvas width="400" height="400" id="canvas"></canvas>
</body>
<script>
    function Point(x, y) {
        return {
            x: x,
            y: y
        }
    }

    function toScreen(p) {
        // return new Point(coordO.x + p.x * unitSize, coordO.y - p.y * unitSize);
        // return new Point(p.x * 100, p.y * 100);
        return p;
    }
    var unitSize = 200;
    var coordO = new Point(200, 400);

    //贝塞尔曲线的3个点
    // var p0 = new Point(-1, 0);
    // var p1 = new Point(1, -1);
    // var p2 = new Point(2, 2);
    var p0 = new Point(250, 30);
    var p1 = new Point(380, 380);
    var p2 = new Point(40, 250);

    //直线上的两个点
    // var lineP0 = new Point(-2, -2);
    // var lineP1 = new Point(4, 14 / 5);
    var lineP0 = new Point(300, 50);
    var lineP1 = new Point(275.90, 300);


    //根据两点式求出的直线一般式系数
    var lineA = (lineP1.y - lineP0.y);
    var lineB = (lineP0.x - lineP1.x);
    var lineC = (lineP1.x * lineP0.y - lineP1.y * lineP0.x);

    //贝塞尔曲线x分量的3个系数（可在连载十七中找到这公式）
    var ax = p0.x - 2 * p1.x + p2.x;
    var bx = 2 * p1.x - 2 * p0.x;
    var cx = p0.x;

    //贝塞尔曲线y分量的3个系数（可在连载十七中找到这公式）
    var ay = p0.y - 2 * p1.y + p2.y;
    var by = 2 * p1.y - 2 * p0.y;
    var cy = p0.y;

    //At+Bt^2+C=0
    //一元二次方程的3个系数
    var squareFormulaA = lineA * ax + lineB * ay;
    var squareFormulaB = lineA * bx + lineB * by;
    var squareFormulaC = lineA * cx + lineB * cy + lineC;
    console.log(squareFormulaA, squareFormulaB, squareFormulaC);
    var ts = [];

    if (squareFormulaA != 0) {
        //接着求根公式
        var delta = squareFormulaB * squareFormulaB - 4 * squareFormulaA * squareFormulaC;
        console.log(delta);
        //delta小于0时无实数解
        if (delta >= 0) {
            var t1 = (- squareFormulaB + Math.sqrt(delta)) / 2 / squareFormulaA;
            var t2 = (- squareFormulaB - Math.sqrt(delta)) / 2 / squareFormulaA;
            if (t1 >= 0 && t1 <= 1) {
                ts.push(t1);
            }
            if (t2 >= 0 && t2 <= 1) {
                ts.push(t2);
            }
        }
    } else if (squareFormulaB != 0) {
        var t = - squareFormulaC / squareFormulaB;
        if (t >= 0 && t <= 1) {
            ts.push(t);
        }

    }

    var screenP0 = toScreen(p0);
    var screenP1 = toScreen(p1);
    var screenP2 = toScreen(p2);

    var screenLineP0 = toScreen(lineP0);
    var screenLineP1 = toScreen(lineP1);

    var canvas = document.getElementById("canvas");
    var context = canvas.getContext("2d");
    context.lineWidth = 0.5;
    context.strokeStyle = "#0000cc";

    //绘制贝塞尔曲线
    context.beginPath();
    context.moveTo(screenP0.x, screenP0.y);
    context.quadraticCurveTo(screenP1.x, screenP1.y, screenP2.x, screenP2.y);
    context.stroke();
    context.closePath();

    //绘制直线
    context.beginPath();
    context.moveTo(screenLineP0.x, screenLineP0.y);
    context.lineTo(screenLineP1.x, screenLineP1.y);
    context.stroke();
    context.closePath();

    context.fillStyle = "#cc0000";

    //绘制交点
    for (var i = 0, len = ts.length; i < len; i++) {
        //把t代入到参数方程中求出xy
        var t = ts[i];
        var x = ax * t * t + bx * t + cx;
        var y = ay * t * t + by * t + cy;
        console.log(x, y);
        var toScreenP = toScreen(new Point(x, y));
        context.beginPath();
        context.arc(toScreenP.x, toScreenP.y, 5, 0, Math.PI * 2, true);
        context.fill();
        context.closePath();
    }

    console.log('===', BesselStraightFocus(lineP0, lineP1, p0, p1, p2))

    /* 
        计算贝塞尔曲线和直线的交点
        @lineP0, lineP1 {Point} 表示直线的两个定点
        @p0, p1, p2 {Point} 贝塞尔曲线的三个控制：p1为控制点，其他两个为开始和结束点
    */
    function BesselStraightFocus(lineP0, lineP1, p0, p1, p2) {
        //根据两点式求出的直线一般式系数
        var lineA = (lineP1.y - lineP0.y);
        var lineB = (lineP0.x - lineP1.x);
        var lineC = (lineP1.x * lineP0.y - lineP1.y * lineP0.x);

        //贝塞尔曲线x分量的3个系数（可在连载十七中找到这公式）
        var ax = p0.x - 2 * p1.x + p2.x;
        var bx = 2 * p1.x - 2 * p0.x;
        var cx = p0.x;

        //贝塞尔曲线y分量的3个系数（可在连载十七中找到这公式）
        var ay = p0.y - 2 * p1.y + p2.y;
        var by = 2 * p1.y - 2 * p0.y;
        var cy = p0.y;

        //At+Bt^2+C=0
        //一元二次方程的3个系数
        var squareFormulaA = lineA * ax + lineB * ay;
        var squareFormulaB = lineA * bx + lineB * by;
        var squareFormulaC = lineA * cx + lineB * cy + lineC;
        console.log(squareFormulaA, squareFormulaB, squareFormulaC);
        var ts = [];

        if (squareFormulaA != 0) {
            //接着求根公式
            var delta = squareFormulaB * squareFormulaB - 4 * squareFormulaA * squareFormulaC;
            console.log(delta);
            //delta小于0时无实数解
            if (delta >= 0) {
                var t1 = (- squareFormulaB + Math.sqrt(delta)) / 2 / squareFormulaA;
                var t2 = (- squareFormulaB - Math.sqrt(delta)) / 2 / squareFormulaA;
                if (t1 >= 0 && t1 <= 1) {
                    ts.push(t1);
                }
                if (t2 >= 0 && t2 <= 1) {
                    ts.push(t2);
                }
            }
        } else if (squareFormulaB != 0) {
            var t = - squareFormulaC / squareFormulaB;
            if (t >= 0 && t <= 1) {
                ts.push(t);
            }

        }
        var focus = [];
        //绘制交点
        for (var i = 0, len = ts.length; i < len; i++) {
            //把t代入到参数方程中求出xy
            var t = ts[i];
            var x = ax * t * t + bx * t + cx;
            var y = ay * t * t + by * t + cy;
            console.log(x, y);
            focus.push([x, y])
        }
        return focus;
    }

</script>
</body>

</html>